package com.carlinfo.common.dao.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.carlinfo.common.dao.IBaseDao;
import com.carlinfo.common.util.DbUtil;
import com.carlinfo.common.util.PageInfoUtil;

public abstract class BaseDaoImpl<T>  implements IBaseDao<T>
{
	protected Logger logger = LogManager.getLogger();
	
	protected  Object pojoObj ;
	/**
	 * 	CUD 全部 调用
	 * */
	protected int executeJDBC(String sql , List<Object> paramsList 
			, Map<String, Object> resultMap)
	{
		DbUtil dbUtil = DbUtil.getInstance();
		Connection con = dbUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			pst = con.prepareStatement(sql , Statement.RETURN_GENERATED_KEYS);
		
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				
				/*参数一  第几个?  参数二 是值	*/
				pst.setObject(count, val);
				count ++ ;
			}
			
			int res = pst.executeUpdate();
			/*	设置参数中的id	*/
			rs = pst.getGeneratedKeys();
			/*	获取id	*/
			if(rs.next())
			{
				/*	不知道参数是什么 
				 * 	可以以直接填写 数据库列 
				 * 	ID在第一列
				 * */
				int id = rs.getInt(1);
				resultMap.put("id", id);
			}
			
			return res;
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(con, pst, rs);
		}
		return 0;
	}
	/**
	 * 	CUD 全部 调用
	 * */
	protected int executeJDBC(String sql , List<Object> paramsList )
	{
		DbUtil dbUtil = DbUtil.getInstance();
		Connection con = dbUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			pst = con.prepareStatement(sql);
		
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				
				/*参数一  第几个?  参数二 是值	*/
				pst.setObject(count, val);
				count ++ ;
			}
			
			int res = pst.executeUpdate();
			
			return res;
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(con, pst, rs);
		}
		return 0;
	}
	/**
	 *	查询一条记录
	 *	准备语句 
	 *	为占位符赋值 list中传入什么类型都可以 
	 */
	protected T findOneJDBC(String sql , List<Object> paramsList)
	{

		DbUtil dbUtil = DbUtil.getInstance();
		/*	获取连接	*/
		Connection con = dbUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			pst = con.prepareStatement(sql);
			
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count ++ ; 
			}
			/* 查询 */
			rs = pst.executeQuery();
			if(rs.next())
			{
				/*	不知道参数是什么 
				 * 	可以以直接填写 数据库列 
				 * 	ID在第一列
				 * */
				T t = converFromDb(rs);
				return t ;
				
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			dbUtil.closeAll(con, pst, rs);
		}
		return null;
	}
	/**
	 * 	查询多条 两种情况 一种分页 
	 * 	一种不分页
	 * */
	protected List<T> findListByPage(PageInfoUtil pageInfoUtil , String sql , List<Object> paramsList)
	{
		/*	存放查询结果	*/
		List<T> resultList = new ArrayList<T>();
		
		DbUtil dbUtil = DbUtil.getInstance();
		Connection con = dbUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			int count ;
			
			if(pageInfoUtil != null)
			{
				
				/*	在此处拼装Sql语句  用传参  传入分页工具类 为占位符赋值	*/
				/*---    数据库的总记录数  --	*/
				/*	spl 语句 select count(*) from a_dynasty 	
				 *	拆分 拼装sql 语句
				 */	
				String  formIndex = "from"; 
				/*	意思是 从from 截取  一直到sql 结束	*/
				String countSql = "select count(*) " + 
						sql.substring(sql.indexOf(formIndex), sql.length());
				this.logger.info("countSQL:{} 参数 {}",countSql , paramsList);
				/*	执行拼装之后的Sql语句	*/
				pst = con.prepareStatement(countSql);
				count = 1;
				for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
				{
					Object val = (Object) iterator.next();
					pst.setObject(count, val);
					count ++ ;
				}
				/*	执行sql	*/
				rs = pst.executeQuery();
				if(rs.next())
				{
					int totalRecord = rs.getInt(1);
					/*	为总条数赋值	*/
					pageInfoUtil.setTotalRecord(totalRecord);
				}
				/*	关闭连接	*/
				rs.close();
				pst.close();
				/*---------传入分页 limit--------*/
				sql += " limit ? , ? ";
				paramsList.add(pageInfoUtil.getCurrentRecord());
				paramsList.add(pageInfoUtil.getPageSize());
			}
			this.findList(sql, paramsList);
		} catch (SQLException e)
		{
			logger.error("朝代操作:查询多条记录失败",e);
		}finally
		{
			dbUtil.closeAll(con, pst, rs);
		}
		return Collections.emptyList();
	}
	/**
	 * 多条查询不分页
	 * */
	protected List<T> findList(String sql, List<Object> paramsList)
	{
		/*	存放的是 查询的结果	*/
		List<T> resultList = new ArrayList<T>();
		
		DbUtil dbUtil = DbUtil.getInstance();
		Connection con = dbUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try
		{
			this.logger.info("sql:{} 参数:{}",sql,paramsList);
			/*	预处理sql语句	*/
			pst = con.prepareStatement(sql);
			/*	为占位符赋值	*/
			int count = 1;
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object val = (Object) iterator.next();
				pst.setObject(count, val);
				count ++ ;
			}
			rs = pst.executeQuery();
			while (rs.next())
			{	
				/*	查询数据	*/
				T t = converFromDb(rs);
				/*	放到 集合中	*/
				resultList.add(t);
			}
			return resultList ;
			
		} catch (SQLException e)
		{
			logger.error("查询多条记录失败",e);
		}finally
		{
			dbUtil.closeAll(con, pst, rs);
		}
		/*	放置报空指针	*/
		return Collections.emptyList();
	}
	/**
	 * 抽象类 谁调用谁实现
	 * */
	protected  T converFromDb(ResultSet rs) 
			throws SQLException
	{
		/*	应用反射从pojo中列出所有属性	*/
		/*	获得所有属性	*/
		Class cla = pojoObj.getClass();
		try
		{
			/*	指定对象  放的什么自己知道	*/
			T valObj =(T)cla.newInstance();
			/*	列出所有的属性	*/
			Field[] allFields = cla.getDeclaredFields();
			/*	循环打印所有属性	*/
			for (int i = 0; i < allFields.length; i++)
			{
				Field field = allFields[i];
				/*	这里要自动补异常 
				 * 	数据库属性类型 和pojo属性类型有冲突
				 * 	*/
				try
				{
					/*	属性的名字和表的名字一样	*/
					String fileName = field.getName();
					/*	获取数据库的值
					 * 	整数位第几列
					 * 	字符串位 列的别名
					 * 	*/
					Object val = rs.getObject(fileName);
					/*	解决网页出现的异常	*/
					if("byte".equalsIgnoreCase(field.getType().getName())
							|| "int".equalsIgnoreCase(field.getType().getName())
							|| "double".equalsIgnoreCase(field.getType().getName())
							|| String.class.getName().equalsIgnoreCase(field.getType().getName())
							|| Date.class.getName().equalsIgnoreCase(field.getType().getName()))
						{
							/*	如果属性要是Str结尾,不允许使用反射赋值	*/
							if(fileName.toLowerCase().endsWith("str"))
							{
								continue ;
							}
						}else
						{
							continue ; 
						}
					/*	将值赋值到对象中
					 * 	读写器的首字母要大写  拆分字符串  截取  转大写 拼装
					 * */
					String setName = "set" + fileName.substring(0, 1).toUpperCase()
							+ fileName.substring(1,fileName.length());
					/* 	参数一  方法名
					 * 	参数二 形参
					 * 	方法定义
					 * */
					Method setMethod = cla.getMethod(setName, field.getType());
					/*	处理个别的类型	*/
					if("byte".equalsIgnoreCase(field.getType().getName()))
					{
						setMethod.invoke(valObj, Byte.valueOf(val + ""));
					}else if("double".equalsIgnoreCase(field.getType().getName()))
					{
						setMethod.invoke(valObj, Double.valueOf(val + ""));
					}else
					{
						/*	调用方法
						 * 	参数一 对象
						 * 	参数二 实现
						 * 	返回值 方法的返回值
						 * */
						setMethod.invoke(valObj, val);
					}
					
				}catch (Exception e) 
				{
					this.logger.error("赋值失败了",e);
				}
			}
		} catch (InstantiationException | IllegalAccessException e)
		{
			this.logger.error("从数据库中赋值给对象失败了;",e);
		}
		return null ;
	}
}
